import { ShapeBox } from "./shape-box-interface";
import { BoxStyle } from "./box-style-model";
import { ControllerPoint } from "../../point-model/controller-point";
import { CommonUtil } from "../../../../util/common-util";
import { ArchorPoint } from "../../point-model/archor-point";
import { BoxService } from "../../../service/box.service";
import { Operation } from "../../operation.model";
import { PointBase } from "../../point-model/point-related/point-base";
import { RotatePoint } from "../../point-model/rotate-point";
import { StyleBase } from "../../style-base.model";

export class ShapeBoxBase extends Operation implements ShapeBox {
    id: string;
    selected: boolean;

    hasCanvas: boolean = true;
    style: BoxStyle;
    scaleData;
    //基础的canvas四个对角点,角度的sin和cos值，以及canvas实际长宽和div长宽
    baseData;

    children?: ShapeBox[];
    points: PointBase[][];


    getDivSize(data?) {
        if (!data) {
            data = {
                width: this.style.rwidth,
                height: this.style.rheight,
                deg: this.style.deg
            }
        }
        let deg = data.deg;
        let sin = Math.abs(Math.sin(deg));
        let cos = Math.abs(Math.cos(deg));
        return {
            width: (data.width * cos + data.height * sin),
            height: (data.width * sin + data.height * cos)
        }
    }

    genCtlPoints(): PointBase[] {
        let points: PointBase[] = [];
        let xmv = this.getWidth() - 20;
        let ymv = this.getHeight() - 20;
        points.push(new ControllerPoint({
            belongTo: this,
            getData: data => data.points[0]
        }));
        points.push(new ControllerPoint({
            belongTo: this,
            getData: data => data.points[1]
        }));
        points.push(new ControllerPoint({
            belongTo: this,
            getData: data => data.points[2]
        }));
        points.push(new ControllerPoint({
            belongTo: this,
            getData: data => data.points[3]
        }));
        return points;
    }
    genArcPoints(): PointBase[] {
        let points: PointBase[] = [];
        points.push(new ArchorPoint({
            belongTo: this,
            getData: data => data.points[4]
        }));
        points.push(new ArchorPoint({
            belongTo: this,
            getData: data => data.points[5]
        }));
        points.push(new ArchorPoint({
            belongTo: this,
            getData: data => data.points[6]
        }));
        points.push(new ArchorPoint({
            belongTo: this,
            getData: data => data.points[7]
        }));
        return points;
    }
    genRtPoints() {
        let points: PointBase[] = [];
        points.push(new RotatePoint({
            belongTo: this,
            getData: data => {
                return {
                    left: data.points[4].left + data.pwh * data.sin / 2, top: data.points[4].top - data.pwh * data.cos / 2
                }
            }
        }));
        return points;
    }
    genPoints() {
        this.points = [[], this.genArcPoints(), []];
    }
    getBaseData() {
        let cursors = ["nw-resize", "ne-resize", "se-resize", "sw-resize"];
        let data = {
            top: CommonUtil.px2num(this.style.top),
            left: CommonUtil.px2num(this.style.left),
            right: 0,
            bottom: 0,
            width: this.getWidth(),
            height: this.getHeight(),
            rWidth: this.style.rwidth,
            rHeight: this.style.rheight,
            sin: Math.sin(this.style.deg),
            cos: Math.cos(this.style.deg)
        };
        data.right = data.left + data.width;
        data.bottom = data.top + data.height;
        let points = [{
            left: (data.width - (data.rWidth * data.cos - data.rHeight * data.sin)) / 2 + data.left,
            top: (data.height - (data.rWidth * data.sin + data.rHeight * data.cos)) / 2 + data.top
        }, {
            left: (data.width + (data.rWidth * data.cos + data.rHeight * data.sin)) / 2 + data.left,
            top: (data.height + (data.rWidth * data.sin - data.rHeight * data.cos)) / 2 + data.top
        }, {
            left: (data.width + (data.rWidth * data.cos - data.rHeight * data.sin)) / 2 + data.left,
            top: (data.height + (data.rWidth * data.sin + data.rHeight * data.cos)) / 2 + data.top
        }, {
            left: (data.width - (data.rWidth * data.cos + data.rHeight * data.sin)) / 2 + data.left,
            top: (data.height - (data.rWidth * data.sin - data.rHeight * data.cos)) / 2 + data.top
        }];
        for (let i = 0, j = Math.floor((this.style.deg + Math.PI / 4) * 2 / Math.PI); i < 4; i++) {
            points[i]["cursor"] = cursors[(i + j) % 4];
            points.push({
                left: (points[i].left + points[(i + 1) % 4].left) / 2,
                top: (points[i].top + points[(i + 1) % 4].top) / 2,
            });
        }
        this.baseData = {
            ...data,
            points: points
        }
        return this.baseData;
    }
    in() {
        this.showPoints([...this.points[1]], true);
    }
    select(e) {
        super.select(e);
        this.allPoints(true);
        this.selected = true;
    }
    out() {
        this.allPoints(false);
        this.selected = false;
    }
    allPoints(visible: boolean) {
        let points = [];
        for (let i = 0; i < this.points.length; i++) {
            points = [...points, ...this.points[i]];
        }
        this.showPoints(points, visible);
    }
    showPoints(points: PointBase[], isShow: boolean) {
        for (let point of points) {
            isShow ? point.show() : point.hide();
        }
    }
    getId() {
        return this.id;
    }
    scale(scale) {
        this.scaleData = scale;
        let sin = Math.sin(this.oldStyle.deg);
        let cos = Math.cos(this.oldStyle.deg);
        // this.style.rwidth = this.oldStyle.rwidth * Math.sqrt(Math.pow(scale.x * cos, 2) + Math.pow(scale.y * sin, 2));
        // this.style.rheight = this.oldStyle.rheight * Math.sqrt(Math.pow(scale.x * sin, 2) + Math.pow(scale.y * cos, 2));
        this.style.rwidth = this.oldStyle.rwidth * scale.x;
        this.style.rheight = this.oldStyle.rheight * scale.y;
        //重新计算div大小
        let data = this.getDivSize();
        this.style.height = data.height + "px";
        this.style.width = data.width + "px";

        //根据固定点的位移反向移动div，使固定点看起来不动
        let left = CommonUtil.px2num(this.oldStyle.left);
        let top = CommonUtil.px2num(this.oldStyle.top);

        this.style.left = left + (left - scale.fixedX) * (scale.x - 1) + "px";
        this.style.top = top + (top - scale.fixedY) * (scale.y - 1) + "px";

        this.reRender();
        this.scaleData = null;
    }
    rotate(center) {
        if (center.deg) {
            this.style.deg = center.deg;
        } else {
            this.style.deg = this.oldStyle.deg + center.rotate;
        }
        
        //重新计算div大小
        let data = this.getDivSize();
        let baseData = {
            width: CommonUtil.px2num(this.oldStyle.width),
            height: CommonUtil.px2num(this.oldStyle.height),
            left: CommonUtil.px2num(this.oldStyle.left),
            top: CommonUtil.px2num(this.oldStyle.top)
        }
        //固定中心点
        let oldCenter = {
            x: (data.width - baseData.width) / 2,
            y: (data.height - baseData.height) / 2
        }
        this.style.height = data.height + "px";
        this.style.width = data.width + "px";
        this.style.left = baseData.left - oldCenter.x + "px";
        this.style.top = baseData.top - oldCenter.y + "px";
        
        if (center.x || center.y) {
            //渲染完毕，处理旋转中心问题
            //当前box与旋转中心的偏移量
            let p = {
                x: baseData.left + baseData.width / 2 - center.x,
                y: baseData.top + baseData.height / 2 - center.y
            }
            let oriDeg = 0;
            let length = Math.sqrt(Math.pow(p.x, 2) + Math.pow(p.y, 2));
            if (length == 0) {
                this.reRender();
                return;
            }
            let cos1 = p.x / length;
            let sin1 = p.y / length;
            let cos2 = Math.cos(center.rotate);
            let sin2 = Math.sin(center.rotate);
            //旋转后偏移量
            let np = {
                x: (cos1 * cos2 - sin1 * sin2) * length,
                y: (sin1 * cos2 + cos1 * sin2) * length
            }
            this.style.left = CommonUtil.px2num(this.style.left) - p.x + np.x + "px";
            this.style.top = CommonUtil.px2num(this.style.top) - p.y + np.y + "px";
        }
        this.reRender();

    }

    reRender() {
        this.paint();
        this.renderPoints();
    }
    renderPoints() {
        for (let points of this.points) {
            for (let point of points) {
                point.render();
            }
        }
    }

    canvasMove(e): boolean {
        let relativeE = {
            x: e.offsetX - this.baseData.left + this.padding,
            y: e.offsetY - this.baseData.top + this.padding
        }
        let point = this.configPoint(relativeE)
        if (this.ctx.isPointInPath(point.x, point.y)) {
            this.boxService.cursor("crosshair");
            if (this.ctx.isPointInPath(relativeE.x, relativeE.y)) {
                this.boxService.cursor("move");
            }
            return true;
        } else {
            return false;
        }
    }
    //扩大连线区间
    configPoint({ x, y }) {
        let canvasWidth = this.getWidth() + this.padding * 2;
        let canvasHeight = this.getHeight() + this.padding * 2;
        let center = {
            x: canvasWidth / 2,
            y: canvasHeight / 2
        }
        let rateX = this.style.rwidth / (this.style.rwidth + 6);
        let rateY = this.style.rheight / (this.style.rheight + 6);
        return {
            x: rateX * (x - center.x) + center.x,
            y: rateY * (y - center.y) + center.y
        }
    }

    constructor(data) {
        super();
        if (data == null) {
            return;
        }
        let checked = this.boxService.generateId(data.id);
        if (!checked) {
            throw new Error("id exists");
        } else if (checked != true) {
            data.id = checked;
        }
        this.id = data.id;
        data.left += "px";
        data.top += "px";
        data.rwidth = data.width;
        data.rheight = data.height;

        let deg = data.deg ? data.deg : 0
        let divSize = this.getDivSize({
            width: data.width,
            height: data.height,
            deg: deg
        });

        data.width = divSize.width + "px";
        data.height = divSize.height + "px";
        this.style = new BoxStyle(data);

        this.style.rwidth = data.rwidth;
        this.style.rheight = data.rheight;
        this.style.lineWidth = 2;
        this.style.deg = deg;
        this.genPoints();

        console.log(this)
    }
}